package com.cloud.common.log;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
@Aspect
@Order(Ordered.HIGHEST_PRECEDENCE)
@Component
public class LogInterceptor {
    private Map<Method, Expression> expressionMap = new ConcurrentHashMap<>();
    private ExpressionParser parser = new SpelExpressionParser();
    private static final String RESULT_NAME = "result";

    @Around("@annotation(com.cloud.common.log.LogMsg)")
    public Object doLogMessage(ProceedingJoinPoint point) throws Throwable {
        Object result = point.proceed();
        handleMessage(point, result);
        return result;
    }

    /**
     * 处理消息
     *
     * @param point
     * @param result
     */
    private void handleMessage(ProceedingJoinPoint point, Object result) {
        try {
            Expression expression = getExpression(point);
            if (expression != null) {
                // 解析参数
                Map<String, Object> parameterMap = parseParameters(point);
                parameterMap.put(RESULT_NAME, result);

                // 设置EL表达式上下文
                StandardEvaluationContext evalContext = new StandardEvaluationContext();
                evalContext.setVariables(parameterMap);

                // 从表达式获取日志输出
                String message = (String) expression.getValue(evalContext);
                log.info(message);
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

    /**
     * 解析参数
     *
     * @param point
     * @return Map<String, Object>
     */
    private Map<String, Object> parseParameters(ProceedingJoinPoint point) {
        Map<String, Object> parameterMap = new HashMap<>();
        MethodSignature methodSignature = (MethodSignature) point.getSignature();
        String[] parameterNames = methodSignature.getParameterNames();
        if (parameterNames != null && parameterNames.length > 0) {
            Object[] parameterValues = point.getArgs();
            for (int i = 0; i < parameterNames.length; i++) {
                parameterMap.put(parameterNames[i], parameterValues[i]);
            }
        }
        return parameterMap;
    }

    /**
     * 获取表达式
     *
     * @param point
     * @return Expression
     */
    private Expression getExpression(ProceedingJoinPoint point) {
        MethodSignature methodSignature = (MethodSignature) point.getSignature();
        Method method = methodSignature.getMethod();
        String message = method.getAnnotation(LogMsg.class).message();
        if (StringUtils.isEmpty(message)) {
            return null;
        }

        // 从缓存获取，没有则生成后放入缓存
        Expression expression = expressionMap.get(method);
        if (expression == null) {
            expression = parser.parseExpression(message);
            expressionMap.put(method, expression);
        }
        return expression;
    }
}
